﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Drawing;
using ArcGIS.Core.Data;
using ArcGIS.Core.CIM;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using Microsoft.Win32;

// ACadSharp 写DWG所需
using ACadSharp;
using ACadSharp.Entities;
using ACadSharp.IO;
using ACadSharp.Tables;
using CSMath;
using CadLayer = ACadSharp.Tables.Layer;
using CCTool.Scripts.CusTool2;
using static CCTool.Scripts.LayerExport.Export2CADBySymbols;
using ArcGIS.Desktop.Core;
using System.Windows;
using CCTool.Scripts.ToolManagers.Managers;
using CCTool.Scripts.Manager;
using CCTool.Scripts.ToolManagers.Extensions;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace CCTool.Scripts.LayerExport
{
    /// <summary>
    /// Interaction logic for Export2CADBySymbols.xaml
    /// </summary>
    public partial class Export2CADBySymbols : ArcGIS.Desktop.Framework.Controls.ProWindow
    {
        // 工具设置标签
        readonly string toolSet = "Export2CADBySymbols";

        public Export2CADBySymbols()
        {
            InitializeComponent();

            // 初始化工具设置
            txtDxfPath.Text = BaseTool.ReadValueFromReg(toolSet, "dxfPath");

            // 版本
            //combox_ver.Items.Add("AutoCAD 2000");
            //combox_ver.Items.Add("AutoCAD 2004");
            //combox_ver.Items.Add("AutoCAD 2007");
            combox_ver.Items.Add("AutoCAD 2010");
            combox_ver.Items.Add("AutoCAD 2013");
            combox_ver.Items.Add("AutoCAD 2018");

            combox_ver.SelectedIndex = BaseTool.ReadValueFromReg(toolSet, "ver_index", "0").ToInt();

            RefreshLayersCommand = new RelayCommand(RefreshLayers);

            ExportBoundary = true;
            ExportHatch = true;
            LineWidth = 0.25;
            HatchTransparency = 0; // 0-100

        }

        // 定义一个进度框
        private ProcessWindow processwindow = null;
        string tool_name = "图层带填充图案导出CAD";

        #region 绑定属性


        private bool _exportBoundary;
        public bool ExportBoundary { get; set; }

        private bool _exportHatch;
        public bool ExportHatch { get; set; }

        private double _lineWidth;
        public double LineWidth { get; set; }


        private int _hatchTransparency;
        public int HatchTransparency { get; set; }


        private int _progress;
        public int Progress { get; set; }

        private bool _isProgressIndeterminate;
        public bool IsProgressIndeterminate { get; set; }


        private bool _isProcessing;
        public bool IsProcessing { get; set; }


        private bool _cancelRequested;
        public bool CancelRequested { get; set; }


        private string _logContent = string.Empty;
        public string LogContent { get; set; }


        #endregion

        #region 命令
        public ICommand RefreshLayersCommand { get; }
        public ICommand BrowseOutputPathCommand { get; }
        public ICommand ShowHelpCommand { get; }
        public ICommand CancelCommand { get; }
        public ICommand RunCommand { get; }
        #endregion

        #region 命令实现
        public void RefreshLayers()
        {


            Task.Run(async () =>
            {
                try
                {
                    var temp = new System.Collections.Generic.List<FeatureLayer>();

                    await QueuedTask.Run(() =>
                    {
                        var map = MapView.Active?.Map;
                        if (map == null)
                            return;

                        foreach (var fl in map.Layers.OfType<FeatureLayer>())
                        {
                            if (fl.ShapeType == esriGeometryType.esriGeometryPolygon)
                                temp.Add(fl);
                        }
                    });

                }
                catch (Exception ex)
                {

                }
            });
        }

        #endregion


        #region 工具方法与日志

        // System.Drawing.Color -> ACadSharp.Color（TrueColor）
        private static ACadSharp.Color ToAcadColor(System.Drawing.Color c)
        {
            return new ACadSharp.Color(c.R, c.G, c.B);
        }

        // 构建 Polyline2D 顶点列表（去除重复闭合点）
        private static List<Vertex2D> BuildPolyline2DVertices(List<MapPoint> ring)
        {
            var verts = new List<Vertex2D>();
            foreach (var pt in EnumerateRingCore(ring))
            {
                verts.Add(new Vertex2D(new XYZ(pt.X, pt.Y, 0))); // bulge=0
            }
            return verts;
        }

        // 遍历环点序列且去掉尾部与首点重复
        private static IEnumerable<MapPoint> EnumerateRingCore(List<MapPoint> ring)
        {
            if (ring == null || ring.Count == 0)
                yield break;

            int n = ring.Count;
            bool hasDuplicateClose = n >= 2 && ring[0].IsEqual(ring[n - 1]);
            int len = hasDuplicateClose ? n - 1 : n;
            for (int i = 0; i < len; i++)
                yield return ring[i];
        }

        /// <summary>
        /// 读取图层渲染，返回按行取填充色的方法（支持Simple/UniqueValue/ClassBreaks）。
        /// </summary>
        private async Task<Func<Row, System.Drawing.Color?>> BuildColorGetterAsync(FeatureLayer fl)
        {
            Func<Row, System.Drawing.Color?> result = null;
            await QueuedTask.Run(() =>
            {
                var renderer = fl.GetRenderer();
                if (renderer == null)
                {
                    result = null;
                    return;
                }

                // 简单渲染
                if (renderer is CIMSimpleRenderer simple)
                {
                    var sym = simple.Symbol?.Symbol as CIMPolygonSymbol;
                    var fill = GetFillColor(sym);
                    if (fill == null)
                    {
                        result = null;
                        return;
                    }
                    result = _ => fill;
                    return;
                }

                // 唯一值渲染
                if (renderer is CIMUniqueValueRenderer unique)
                {
                    if (unique.Fields == null || unique.Fields.Length == 0)
                    {
                        result = null;
                        return;
                    }
                    string field = unique.Fields[0];
                    var map = new Dictionary<string, System.Drawing.Color?>();
                    if (unique.Groups != null)
                    {
                        foreach (var g in unique.Groups)
                        {
                            if (g?.Classes == null) continue;
                            foreach (var cls in g.Classes)
                            {
                                var usym = cls.Symbol?.Symbol as CIMPolygonSymbol;
                                var c = GetFillColor(usym);
                                if (cls?.Values == null) continue;
                                foreach (var v in cls.Values)
                                {
                                    if (v?.FieldValues == null || v.FieldValues.Length == 0) continue;
                                    map[v.FieldValues[0]] = c;
                                }
                            }
                        }
                    }
                    result = row =>
                    {
                        try
                        {
                            var idx = row.FindField(field);
                            if (idx < 0) return null;
                            var val = row[idx]?.ToString();
                            if (val == null) return null;
                            if (map.TryGetValue(val, out var col)) return col;
                            return null;
                        }
                        catch { return null; }
                    };
                    return;
                }

                // 分级渲染
                if (renderer is CIMClassBreaksRenderer br)
                {
                    string field = br.Field;
                    var list = new List<(double? min, double? max, System.Drawing.Color? color)>();
                    if (br.Breaks != null)
                    {
                        foreach (var b in br.Breaks)
                        {
                            var bsym = b.Symbol?.Symbol as CIMPolygonSymbol;
                            var col = GetFillColor(bsym);
                            // ArcGIS Pro SDK: 使用上界作为分级阈值
                            list.Add((null, b.UpperBound, col));
                        }
                    }
                    result = row =>
                    {
                        try
                        {
                            var idx = row.FindField(field);
                            if (idx < 0) return null;
                            var valObj = row[idx];
                            if (valObj == null) return null;
                            if (!double.TryParse(valObj.ToString(), out var d)) return null;
                            foreach (var (min, max, col) in list)
                            {
                                var okMin = !min.HasValue || d >= min.Value;
                                var okMax = !max.HasValue || d < max.Value;
                                if (okMin && okMax) return col;
                            }
                            return null;
                        }
                        catch { return null; }
                    };
                    return;
                }

                // 不支持的渲染器
                result = null;
            });
            return result;
        }

        private static System.Drawing.Color? GetFillColor(CIMPolygonSymbol sym)
        {
            if (sym?.SymbolLayers == null) return null;
            foreach (var sl in sym.SymbolLayers)
            {
                if (sl is CIMSolidFill sf)
                {
                    var c = sf.Color;
                    if (c is CIMRGBColor rgb)
                    {
                        int a = (int)Math.Round(rgb.Alpha * 255.0 / 100.0);
                        int r = Math.Clamp((int)Math.Round(rgb.R), 0, 255);
                        int g = Math.Clamp((int)Math.Round(rgb.G), 0, 255);
                        int b = Math.Clamp((int)Math.Round(rgb.B), 0, 255);
                        return System.Drawing.Color.FromArgb(a, r, g, b);
                    }
                    if (c is CIMCMYKColor cmyk)
                    {
                        // 简易CMYK转RGB
                        double c1 = cmyk.C / 100.0, m = cmyk.M / 100.0, y = cmyk.Y / 100.0, k = cmyk.K / 100.0;
                        int r = (int)Math.Round(255 * (1 - c1) * (1 - k));
                        int g = (int)Math.Round(255 * (1 - m) * (1 - k));
                        int b = (int)Math.Round(255 * (1 - y) * (1 - k));
                        int a = (int)Math.Round(cmyk.Alpha * 255.0 / 100.0);
                        return System.Drawing.Color.FromArgb(a, Math.Clamp(r, 0, 255), Math.Clamp(g, 0, 255), Math.Clamp(b, 0, 255));
                    }
                }
            }
            return null;
        }

        // 导出项（一个要素 -> 多个环）
        private class PolygonItem
        {
            public List<List<MapPoint>> Rings { get; set; } = new();
            public System.Drawing.Color Color { get; set; }
            public string LayerName { get; set; }
        }


        /// <summary>
        /// 遍历图层要素，抽取几何环集合、颜色与图层名。
        /// Rings：每个要素内包含多个闭合环（保持原始顺序）。
        /// </summary>
        private async Task<List<PolygonItem>> ExtractPolygonsAsync(FeatureLayer fl, Func<Row, System.Drawing.Color?> colorGetter, Func<Row, string> layerNameGetter = null)
        {
            var results = new List<PolygonItem>();
            await QueuedTask.Run(() =>
            {
                using var table = fl.GetTable();
                using var cursor = table.Search(null, false);
                while (cursor.MoveNext())
                {
                    using var row = cursor.Current as Row;
                    if (row is not Feature feat) continue;
                    var poly = feat.GetShape() as Polygon;
                    if (poly == null || poly.IsEmpty) continue;

                    var rings = new List<List<MapPoint>>();
                    foreach (var part in poly.Parts)
                    {
                        var pts = new List<MapPoint>();
                        foreach (var seg in part)
                        {
                            if (pts.Count == 0)
                                pts.Add(seg.StartPoint);
                            pts.Add(seg.EndPoint);
                        }
                        if (pts.Count >= 4)
                        {
                            if (!pts[0].IsEqual(pts[^1]))
                                pts.Add(pts[0]);
                            rings.Add(pts);
                        }
                    }

                    if (rings.Count == 0) continue;
                    var col = colorGetter(row) ?? System.Drawing.Color.FromArgb(255, 200, 200, 200);
                    string lname = null;
                    try { lname = layerNameGetter?.Invoke(row); } catch { lname = null; }
                    if (string.IsNullOrWhiteSpace(lname))
                        lname = $"Fill_{col.R:X2}{col.G:X2}{col.B:X2}";
                    lname = SanitizeLayerName(lname);
                    results.Add(new PolygonItem { Rings = rings, Color = col, LayerName = lname });
                }
            });
            return results;
        }

        /// <summary>
        /// 根据渲染器构建图层名获取器：
        /// - Simple: 固定为图层名
        /// - UniqueValue: 按字段值映射到类标签或字段值
        /// - ClassBreaks: 以分级标签或“≤上界”命名
        /// </summary>
        private async Task<Func<Row, string>> BuildLayerNameGetterAsync(FeatureLayer fl, Func<Row, System.Drawing.Color?> colorGetter)
        {
            Func<Row, string> result = null;
            await QueuedTask.Run(() =>
            {
                var renderer = fl.GetRenderer();
                if (renderer == null)
                {
                    result = null;
                    return;
                }

                // Simple
                if (renderer is CIMSimpleRenderer sr)
                {
                    var baseName = SanitizeLayerName(fl.Name);
                    result = _ => baseName;
                    return;
                }

                // UniqueValue
                if (renderer is CIMUniqueValueRenderer uv)
                {
                    if (uv.Fields == null || uv.Fields.Length == 0)
                    {
                        result = _ => SanitizeLayerName(fl.Name);
                        return;
                    }
                    string field = uv.Fields[0];
                    var dict = new Dictionary<string, string>();
                    if (uv.Groups != null)
                    {
                        foreach (var g in uv.Groups)
                        {
                            if (g?.Classes == null) continue;
                            foreach (var cls in g.Classes)
                            {
                                string name = !string.IsNullOrWhiteSpace(cls.Label) ? cls.Label : null;
                                if (cls?.Values == null) continue;
                                foreach (var v in cls.Values)
                                {
                                    if (v?.FieldValues == null || v.FieldValues.Length == 0) continue;
                                    var key = v.FieldValues[0] ?? string.Empty;
                                    var candidate = name ?? key;
                                    dict[key] = SanitizeLayerName(candidate);
                                }
                            }
                        }
                    }

                    result = row =>
                    {
                        try
                        {
                            var idx = row.FindField(field);
                            if (idx < 0) return SanitizeLayerName(fl.Name);
                            var val = row[idx]?.ToString() ?? string.Empty;
                            if (dict.TryGetValue(val, out var n) && !string.IsNullOrWhiteSpace(n)) return n;
                            return SanitizeLayerName($"{fl.Name}_{val}");
                        }
                        catch { return SanitizeLayerName(fl.Name); }
                    };
                    return;
                }

                // ClassBreaks
                if (renderer is CIMClassBreaksRenderer br)
                {
                    string field = br.Field;
                    var list = new List<(double ub, string name)>();
                    if (br.Breaks != null)
                    {
                        foreach (var b in br.Breaks)
                        {
                            string label = !string.IsNullOrWhiteSpace(b.Label) ? b.Label : $"≤{b.UpperBound}";
                            list.Add((b.UpperBound, SanitizeLayerName(label)));
                        }
                    }
                    result = row =>
                    {
                        try
                        {
                            var idx = row.FindField(field);
                            if (idx < 0) return SanitizeLayerName(fl.Name);
                            var valObj = row[idx];
                            if (valObj == null) return SanitizeLayerName(fl.Name);
                            if (!double.TryParse(valObj.ToString(), out var d)) return SanitizeLayerName(fl.Name);
                            foreach (var (ub, nm) in list)
                            {
                                if (d < ub) return nm;
                            }
                            return SanitizeLayerName(fl.Name);
                        }
                        catch { return SanitizeLayerName(fl.Name); }
                    };
                    return;
                }

                result = _ => SanitizeLayerName(fl.Name);
            });
            return result;
        }

        private static string SanitizeLayerName(string name)
        {
            if (string.IsNullOrWhiteSpace(name)) return "Layer0";
            var invalid = new char[] { '<', '>', '/', '\\', ':', '\"', '?', '*', '|', ',', ';', '=', '[', ']', '{', '}', '(', ')' };
            foreach (var c in invalid)
                name = name.Replace(c, '_');
            name = name.Replace(' ', '_');
            // 图层名不宜过长
            if (name.Length > 60)
                name = name.Substring(0, 60);
            return name;
        }

        private static CadLayer GetOrCreateLayer(CadDocument doc, string layerName, System.Drawing.Color color)
        {
            var safe = SanitizeLayerName(layerName);
            CadLayer layer = null;
            try { layer = doc.Layers[safe]; } catch { layer = null; }
            if (layer == null)
            {
                layer = new CadLayer(safe)
                {
                    Color = new ACadSharp.Color(color.R, color.G, color.B)
                };
                doc.Layers.Add(layer);
            }
            return layer;
        }

        /// <summary>
        /// 设置初始视图：切换到模型空间，并根据全局包络设置 Extents。
        /// 某些查看器会参考 ExtMin/ExtMax 与 TileMode 来初始化打开视图。
        /// </summary>
        private static void ApplyInitialModelView(CadDocument doc, double minx, double miny, double maxx, double maxy)
        {
            try
            {
                // 必须是有效范围
                if (double.IsInfinity(minx) || double.IsInfinity(miny) || double.IsInfinity(maxx) || double.IsInfinity(maxy))
                    return;
                if (maxx <= minx || maxy <= miny)
                    return;

                var header = doc.Header;
                header.ShowModelSpace = true; // 切换到模型空间

                // 设置模型空间范围，Z 统一为 0
                var minPoint = new XYZ(minx, miny, 0);
                var maxPoint = new XYZ(maxx, maxy, 0);
                header.ModelSpaceExtMin = minPoint;
                header.ModelSpaceExtMax = maxPoint;
                var limitsMin = new XY(minx, miny);
                var limitsMax = new XY(maxx, maxy);
                header.ModelSpaceLimitsMin = limitsMin;
                header.ModelSpaceLimitsMax = limitsMax;

                // 设置默认视口高度与中心
                var width = maxx - minx;
                var height = maxy - miny;
                if (width > 0 && height > 0)
                {
                    if (!doc.VPorts.TryGetValue("*ACTIVE", out var vport))
                    {
                        vport = new VPort("*ACTIVE");
                        doc.VPorts.Add(vport);
                    }
                    vport.Center = new XY(minx + width / 2.0, miny + height / 2.0);
                    vport.ViewHeight = height;
                    vport.AspectRatio = width / height;
                }

            }
            catch { }
        }
        #endregion



        private void btn_help_click(object sender, RoutedEventArgs e)
        {
            string url = "https://blog.csdn.net/xcc34452366/article/details/149689230?spm=1001.2014.3001.5501";
            UITool.Link2Web(url);
        }

        private void openDxfPath_Click(object sender, RoutedEventArgs e)
        {
            txtDxfPath.Text = UITool.SaveDialogCAD();
        }


        private void btn_go_click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 获取指标

                string dxfPath = txtDxfPath.Text;
                int ver_index = combox_ver.SelectedIndex;

                // 写入本地

                BaseTool.WriteValueToReg(toolSet, "dxfPath", dxfPath);
                BaseTool.WriteValueToReg(toolSet, "ver_index", ver_index);

                // 版本格式 置换
                ACadVersion ver = ver_index switch
                {
                    0 => ACadVersion.AC1024,
                    1 => ACadVersion.AC1027,
                    2 => ACadVersion.AC1032,
                    _ => ACadVersion.AC1024,
                };



                // 打开进度框
                ProcessWindow pw = UITool.OpenProcessWindow(processwindow, tool_name);
                pw.AddMessageTitle(tool_name);

                Close();

                // 获取图层
                FeatureLayer SelectedPolygonLayer = MapView.Active.GetSelectedLayers().FirstOrDefault() as FeatureLayer;

                _ = Task.Run(async () =>
                {
                    if (SelectedPolygonLayer == null)
                    {
                        return;
                    }
                    if (string.IsNullOrWhiteSpace(dxfPath))
                    {

                        return;
                    }

                    // 1) 构建颜色获取器（支持简单渲染/唯一值/分级渲染）
                    Func<Row, System.Drawing.Color?> colorGetter = await BuildColorGetterAsync(SelectedPolygonLayer);
                    if (colorGetter == null)
                    {

                        return;
                    }
                    // 1.1) 构建图层名称获取器（与渲染器一致）
                    Func<Row, string> layerNameGetter = await BuildLayerNameGetterAsync(SelectedPolygonLayer, colorGetter);
                    if (layerNameGetter == null)
                    {
                        // 回退使用要素类名
                        layerNameGetter = _ => SelectedPolygonLayer.Name;
                    }

                    // 2) 抽取面几何环与颜色

                    var items = await ExtractPolygonsAsync(SelectedPolygonLayer, colorGetter, layerNameGetter);
                    if (items.Count == 0)
                    {

                        return;
                    }


                    // 3) 生成DWG
                    // 路径与权限检查
                    try
                    {
                        var dir = Path.GetDirectoryName(dxfPath);
                        if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                            Directory.CreateDirectory(dir);
                    }
                    catch (Exception ioex)
                    {
                        return;
                    }

                    // 创建文档
                    var doc = new CadDocument();

                    // 应用 DWG 版本（写入 Header）
                    try
                    {
                        doc.Header.Version = ver;
                    }
                    catch { /* 若版本设置异常则沿用库默认值 */ }

                    // 全局包络（用于初始视图定位）
                    double gminx = double.PositiveInfinity, gminy = double.PositiveInfinity;
                    double gmaxx = double.NegativeInfinity, gmaxy = double.NegativeInfinity;

                    foreach (var item in items)
                    {
                        if (CancelRequested)
                        {

                            return;
                        }

                        // 目标图层（按渲染分类）
                        var targetLayer = GetOrCreateLayer(doc, item.LayerName, item.Color);

                        // 边界多段线（使用 Polyline2D）
                        if (ExportBoundary)
                        {
                            foreach (var ring in item.Rings)
                            {
                                // 更新全局包络
                                foreach (var pt in EnumerateRingCore(ring))
                                {
                                    if (pt.X < gminx) gminx = pt.X;
                                    if (pt.Y < gminy) gminy = pt.Y;
                                    if (pt.X > gmaxx) gmaxx = pt.X;
                                    if (pt.Y > gmaxy) gmaxy = pt.Y;
                                }

                                var vertices = BuildPolyline2DVertices(ring);
                                if (vertices.Count >= 2)
                                {
                                    var pl = new Polyline2D(vertices, true);
                                    pl.Color = ToAcadColor(item.Color);
                                    pl.Layer = targetLayer;
                                    // 线宽暂不强制设置，保持 ByLayer，避免与枚举值不匹配
                                    doc.ModelSpace.Entities.Add(pl);
                                }
                            }
                        }

                        // 实体填充（SOLID Hatch）
                        if (ExportHatch)
                        {
                            // 透明度：结合符号Alpha与用户设置（取更透明者），并限制在0-90
                            var alphaPercent = 100 - (int)Math.Round(item.Color.A * 100.0 / 255.0); // 0=不透明,100=全透明
                            var userPercent = Math.Clamp(HatchTransparency, 0, 100);
                            var finalPercent = Math.Clamp(Math.Max(alphaPercent, userPercent), 0, 90);

                            var hatch = new Hatch
                            {
                                IsSolid = true,
                                Color = ToAcadColor(item.Color),
                                Transparency = new Transparency((short)finalPercent)
                            };

                            foreach (var ring in item.Rings)
                            {
                                var bp = new Hatch.BoundaryPath();
                                var edge = new Hatch.BoundaryPath.Polyline
                                {
                                    IsClosed = true
                                };

                                // 顶点（Z 记录 bulge=0）
                                foreach (var pt in EnumerateRingCore(ring))
                                {
                                    // 更新全局包络
                                    if (pt.X < gminx) gminx = pt.X;
                                    if (pt.Y < gminy) gminy = pt.Y;
                                    if (pt.X > gmaxx) gmaxx = pt.X;
                                    if (pt.Y > gmaxy) gmaxy = pt.Y;

                                    edge.Vertices.Add(new XYZ(pt.X, pt.Y, 0));
                                }

                                bp.Edges.Add(edge);
                                hatch.Paths.Add(bp);
                            }

                            hatch.Layer = targetLayer;
                            doc.ModelSpace.Entities.Add(hatch);
                        }
                    }


                    // 设定初始视图为模型空间并定位到要素范围
                    ApplyInitialModelView(doc, gminx, gminy, gmaxx, gmaxy);

                    // 写入DWG
                    try
                    {
                        using (var writer = new DwgWriter(dxfPath, doc))
                        {
                            writer.Write();
                        }

                    }
                    catch (Exception ex)
                    {

                    }
                });


                pw.AddMessageEnd();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message + ee.StackTrace);
                return;
            }

        }

    }

    /// <summary>
    /// 简易RelayCommand
    /// </summary>
    internal class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add { System.Windows.Input.CommandManager.RequerySuggested += value; }
            remove { System.Windows.Input.CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
        public void Execute(object parameter) => _execute();
    }

}
